#include "ezfb_fonts.h"

#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>

/********************************************/
/*              ASCII 8X16                  */
/********************************************/
static u_char g_ascii[]=
{
  /*0x00*/  
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  
  /*0x10*/
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  
  /*0x20*/
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/* */
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x18,0x3c,0x3c,0x3c,0x18,0x18,/*!*/
  0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00,
  0x00,0x66,0x66,0x66,0x24,0x00,0x00,0x00,/*"*/
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x6c,0x6c,0xfe,0x6c,0x6c,
  0x6c,0xfe,0x6c,0x6c,0x00,0x00,0x00,0x00,
  0x18,0x18,0x7c,0xc6,0xc2,0xc0,0x7c,0x06,
  0x86,0xc6,0x7c,0x18,0x18,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0xc2,0xc6,0x0c,0x18,
  0x30,0x60,0xc6,0x86,0x00,0x00,0x00,0x00,
  0x00,0x00,0x38,0x6c,0x6c,0x38,0x76,0xdc,
  0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
  0x00,0x30,0x30,0x30,0x60,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x0c,0x18,0x30,0x30,0x30,0x30,
  0x30,0x30,0x18,0x0c,0x00,0x00,0x00,0x00,
  0x00,0x00,0x30,0x18,0x0c,0x0c,0x0c,0x0c,
  0x0c,0x0c,0x18,0x30,0x00,0x00,0x00,0x00,

  0x00,0x00,0x00,0x00,0x00,0x66,0x3c,0xff,
  0x3c,0x66,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x7e,
  0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x18,0x18,0x18,0x30,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x02,0x06,0x0c,0x18,
  0x30,0x60,0xc0,0x80,0x00,0x00,0x00,0x00,
	
  0x00,0x00,0x7c,0xc6,0xc6,0xce,0xd6,0xd6,
  0xe6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
  0x00,0x00,0x18,0x38,0x78,0x18,0x18,0x18,/*1*/
  0x18,0x18,0x18,0x7e,0x00,0x00,0x00,0x00,
  0x00,0x00,0x7c,0xc6,0x06,0x0c,0x18,0x30,
  0x60,0xc0,0xc6,0xfe,0x00,0x00,0x00,0x00,
  0x00,0x00,0x7c,0xc6,0x06,0x06,0x3c,0x06,
  0x06,0x06,0xc6,0x7c,0x00,0x00,0x00,0x00,
  0x00,0x00,0x0c,0x1c,0x3c,0x6c,0xcc,0xfe,
  0x0c,0x0c,0x0c,0x1e,0x00,0x00,0x00,0x00,
  0x00,0x00,0xfe,0xc0,0xc0,0xc0,0xfc,0x0e,
  0x06,0x06,0xc6,0x7c,0x00,0x00,0x00,0x00,
  0x00,0x00,0x38,0x60,0xc0,0xc0,0xfc,0xc6,
  0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
  0x00,0x00,0xfe,0xc6,0x06,0x06,0x0c,0x18,
  0x30,0x30,0x30,0x30,0x00,0x00,0x00,0x00,
  0x00,0x00,0x7c,0xc6,0xc6,0xc6,0x7c,0xc6,
  0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
  0x00,0x00,0x7c,0xc6,0xc6,0xc6,0x7e,0x06,
  0x06,0x06,0x0c,0x78,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,
  0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,
  0x00,0x18,0x18,0x30,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x06,0x0c,0x18,0x30,0x60,
  0x30,0x18,0x0c,0x06,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0x00,
  0x00,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x60,0x30,0x18,0x0c,0x06,
  0x0c,0x18,0x30,0x60,0x00,0x00,0x00,0x00,
  0x00,0x00,0x7c,0xc6,0xc6,0x0c,0x18,0x18,
  0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x7c,0xc6,0xc6,0xde,0xde,
  0xde,0xdc,0xc0,0x7c,0x00,0x00,0x00,0x00,
  0x00,0x00,0x10,0x38,0x6c,0xc6,0xc6,0xfe,
  0xc6,0xc6,0xc6,0xc6,0x00,0x00,0x00,0x00,
  0x00,0x00,0xfc,0x66,0x66,0x66,0x7c,0x66,
  0x66,0x66,0x66,0xfc,0x00,0x00,0x00,0x00,
  0x00,0x00,0x3c,0x66,0xc2,0xc0,0xc0,0xc0,
  0xc0,0xc2,0x66,0x3c,0x00,0x00,0x00,0x00,
  0x00,0x00,0xf8,0x6c,0x66,0x66,0x66,0x66,
  0x66,0x66,0x6c,0xf8,0x00,0x00,0x00,0x00,
  0x00,0x00,0xfe,0x66,0x62,0x68,0x78,0x68,
  0x60,0x62,0x66,0xfe,0x00,0x00,0x00,0x00,
  0x00,0x00,0xfe,0x66,0x62,0x68,0x78,0x68,
  0x60,0x60,0x60,0xf0,0x00,0x00,0x00,0x00,
  0x00,0x00,0x3c,0x66,0xc2,0xc0,0xc0,0xde,
  0xc6,0xc6,0x66,0x3a,0x00,0x00,0x00,0x00,
  0x00,0x00,0xc6,0xc6,0xc6,0xc6,0xfe,0xc6,
  0xc6,0xc6,0xc6,0xc6,0x00,0x00,0x00,0x00,
  0x00,0x00,0x3c,0x18,0x18,0x18,0x18,0x18,
  0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,
  0x00,0x00,0x1e,0x0c,0x0c,0x0c,0x0c,0x0c,
  0xcc,0xcc,0xcc,0x78,0x00,0x00,0x00,0x00,
  0x00,0x00,0xe6,0x66,0x6c,0x6c,0x78,0x78,
  0x6c,0x66,0x66,0xe6,0x00,0x00,0x00,0x00,
  0x00,0x00,0xf0,0x60,0x60,0x60,0x60,0x60,
  0x60,0x62,0x66,0xfe,0x00,0x00,0x00,0x00,
  0x00,0x00,0xc6,0xee,0xfe,0xfe,0xd6,0xc6,
  0xc6,0xc6,0xc6,0xc6,0x00,0x00,0x00,0x00,
  0x00,0x00,0xc6,0xe6,0xf6,0xfe,0xde,0xce,
  0xc6,0xc6,0xc6,0xc6,0x00,0x00,0x00,0x00,
  0x00,0x00,0x38,0x6c,0xc6,0xc6,0xc6,0xc6,
  0xc6,0xc6,0x6c,0x38,0x00,0x00,0x00,0x00,
  0x00,0x00,0xfc,0x66,0x66,0x66,0x7c,0x60,
  0x60,0x60,0x60,0xf0,0x00,0x00,0x00,0x00,
  0x00,0x00,0x7c,0xc6,0xc6,0xc6,0xc6,0xc6,
  0xc6,0xd6,0xde,0x7c,0x0c,0x0e,0x00,0x00,
  0x00,0x00,0xfc,0x66,0x66,0x66,0x7c,0x6c,
  0x66,0x66,0x66,0xe6,0x00,0x00,0x00,0x00,
  0x00,0x00,0x7c,0xc6,0xc6,0x60,0x38,0x0c,
  0x06,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
  0x00,0x00,0x7e,0x7e,0x5a,0x18,0x18,0x18,
  0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,
  0x00,0x00,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,
  0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
  0x00,0x00,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,
  0xc6,0x6c,0x38,0x10,0x00,0x00,0x00,0x00,
  0x00,0x00,0xc6,0xc6,0xc6,0xc6,0xc6,0xd6,
  0xd6,0xfe,0x6c,0x6c,0x00,0x00,0x00,0x00,
  0x00,0x00,0xc6,0xc6,0x6c,0x6c,0x38,0x38,
  0x6c,0x6c,0xc6,0xc6,0x00,0x00,0x00,0x00,
  0x00,0x00,0x66,0x66,0x66,0x66,0x3c,0x18,
  0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,
  0x00,0x00,0xfe,0xc6,0x86,0x0c,0x18,0x30,
  0x60,0xc2,0xc6,0xfe,0x00,0x00,0x00,0x00,
  0x00,0x00,0x3c,0x30,0x30,0x30,0x30,0x30,
  0x30,0x30,0x30,0x3c,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x80,0xc0,0xe0,0x70,0x38,
  0x1c,0x0e,0x06,0x02,0x00,0x00,0x00,0x00,
  0x00,0x00,0x3c,0x0c,0x0c,0x0c,0x0c,0x0c,
  0x0c,0x0c,0x0c,0x3c,0x00,0x00,0x00,0x00,
  0x10,0x38,0x6c,0xc6,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0xff,0x00,0x00,
  0x30,0x30,0x18,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x78,0x0c,0x7c,
  0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
  0x00,0x00,0xe0,0x60,0x60,0x78,0x6c,0x66,
  0x66,0x66,0x66,0xdc,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x7c,0xc6,0xc0,
  0xc0,0xc0,0xc6,0x7c,0x00,0x00,0x00,0x00,
  0x00,0x00,0x1c,0x0c,0x0c,0x3c,0x6c,0xcc,
  0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x7c,0xc6,0xfe,
  0xc0,0xc0,0xc6,0x7c,0x00,0x00,0x00,0x00,
  0x00,0x00,0x38,0x6c,0x64,0x60,0xf0,0x60,
  0x60,0x60,0x60,0xf0,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x76,0xcc,0xcc,
  0xcc,0xcc,0xcc,0x7c,0x0c,0xcc,0x78,0x00,
  0x00,0x00,0xe0,0x60,0x60,0x6c,0x76,0x66,
  0x66,0x66,0x66,0xe6,0x00,0x00,0x00,0x00,
  0x00,0x00,0x18,0x18,0x00,0x38,0x18,0x18,
  0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,
  0x00,0x00,0x06,0x06,0x00,0x0e,0x06,0x06,
  0x06,0x06,0x06,0x06,0x66,0x66,0x3c,0x00,
  0x00,0x00,0xe0,0x60,0x60,0x66,0x6c,0x78,
  0x78,0x6c,0x66,0xe6,0x00,0x00,0x00,0x00,
  0x00,0x00,0x38,0x18,0x18,0x18,0x18,0x18,
  0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0xec,0xfe,0xd6,
  0xd6,0xd6,0xd6,0xd6,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0xdc,0x66,0x66,
  0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x7c,0xc6,0xc6,
  0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0xdc,0x66,0x66,
  0x66,0x66,0x66,0x7c,0x60,0x60,0xf0,0x00,
  0x00,0x00,0x00,0x00,0x00,0x76,0xcc,0xcc,
  0xcc,0xcc,0xcc,0x7c,0x0c,0x0c,0x1e,0x00,
  0x00,0x00,0x00,0x00,0x00,0xdc,0x76,0x62,
  0x60,0x60,0x60,0xf0,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x7c,0xc6,0x60,
  0x38,0x0c,0xc6,0x7c,0x00,0x00,0x00,0x00,
  0x00,0x00,0x10,0x30,0x30,0xfc,0x30,0x30,
  0x30,0x30,0x36,0x1c,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0xcc,0xcc,0xcc,
  0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66,
  0x66,0x66,0x3c,0x18,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0xc6,0xc6,0xc6,
  0xd6,0xd6,0xfe,0x6c,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0xc6,0x6c,0x38,
  0x38,0x38,0x6c,0xc6,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0xc6,0xc6,0xc6,
  0xc6,0xc6,0xc6,0x7e,0x06,0x0c,0xf8,0x00,
  0x00,0x00,0x00,0x00,0x00,0xfe,0xcc,0x18,
  0x30,0x60,0xc6,0xfe,0x00,0x00,0x00,0x00,
  0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,
  0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,
  0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,
  0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,
  0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,
  0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe
}; 

static FILE * g_fp_uni = NULL ;  // unicode file for unicode --> gb2312 convert 
static FILE * g_fp_gbk = NULL ;  // gb2312 file for unicode --> gb2312 convert 
static FILE * g_fp_hzk12 = NULL ; // 12x12 hz data file 
static FILE * g_fp_hzk16 = NULL ; // 16x16 hz data file 

// open gb2312 hzk, unicode gbk convert files...
// if no error happened returns 0, else not null 
int ezfb_font_open()
{
  // open unicode file 
  if(!g_fp_uni) {
    if((g_fp_uni = fopen(FILE_UNICODE, "rb")) == NULL) return -1 ; 
  }

  // open gb2312 file 
  if(!g_fp_gbk) {
    if((g_fp_gbk = fopen(FILE_GB2312, "rb")) == NULL) return -2 ; 
  }

  // open hzk12 file 
  if(!g_fp_hzk12) {
    if((g_fp_hzk12 = fopen(FILE_HZK12, "rb")) == NULL) return -3 ; 
  }

  // open hzk16 file 
  if(!g_fp_hzk16) {
    if((g_fp_hzk16 = fopen(FILE_HZK16, "rb")) == NULL) return -4 ; 
  }
  return 0 ; 
}

void ezfb_font_close() 
{
  if(g_fp_hzk16) {
    fclose(g_fp_hzk16) ; 
    g_fp_hzk16 = NULL ; 
  }
  
  if(g_fp_hzk12) {
    fclose(g_fp_hzk12) ; 
    g_fp_hzk12 = NULL ; 
  }

  if(g_fp_gbk) {
    fclose(g_fp_gbk) ; 
    g_fp_gbk = NULL ; 
  }
  
  if(g_fp_uni) {
    fclose(g_fp_uni) ; 
    g_fp_uni = NULL ; 
  }
}

// convert single unicode char into gb2312 char 
// binary lookup the unicode and gb2312 map 
// gb  : result gb2312 encoded char 
// uni : input unicode char
// return 1 means find the specified unicode -> gb2312 char
// return 0 means no matched char
int ezfb_uni2gb_chr(u_char * gb, u_char * uni)
{
	u_short   uni_obj = *((u_short *)(uni)) ; 
	u_short   uni_val = 0 ;  

	int start_idx = 0 ; 
	int end_idx = UNI_CHR_COUNT ; // 7445 unicode 
	int mid_idx = (start_idx + end_idx) / 2 ; 
	gb[0] = 0xa1 ; 
	gb[1] = 0xf2 ; 
	while((end_idx - start_idx) > 1) {
		fseek(g_fp_uni, mid_idx * 2, SEEK_SET) ; 
		fread(&uni_val, 2, 1, g_fp_uni) ;
		if(uni_val < uni_obj) start_idx = mid_idx ; 
		else if(uni_val > uni_obj) end_idx = mid_idx ; 
		else {
			fseek(g_fp_gbk, mid_idx * 2, SEEK_SET) ; 
			fread(gb, 2, 1, g_fp_gbk) ; 
			gb[0] ^= gb[1] ^= gb[0] ^= gb[1] ; 
			return 1 ; 
		}
		mid_idx = (start_idx + end_idx) / 2 ; 
	}
	return 0 ; 
}

// used for convert unicode string into gb2312 code
// gb  : result gb2312 encoded string 
// uni : input unicode encoded string
// return gb2312 string length in bytes   
int ezfb_uni2gb_str(u_char * gb, u_char * uni) 
{
	u_short * original = (u_short *)(uni) ; 
	u_char  * gbchr = gb ; 
	while(*original != 0) {
		if(*uni <= 0x7f && *(uni+1) == 0) {
			// ascii char, no need to be converted
			*gbchr++ = *uni ;
		} else {
			ezfb_uni2gb_chr(gbchr, uni) ; 
			gbchr += 2 ; 
		}
		uni += 2 ; 
		original = (u_short *)(uni) ; 
	}  
	*gbchr = 0 ;
	return (int)(gbchr - gb) ;  
}

// convert utf8 string into unicode string
// uni  : result unicode encoded string
// utf8 : input utf8 encoded string 
// return unicode string length in bytes 
int ezfb_utf82uni_str(u_char * uni,u_char * utf8, int buf_size)
{
        int i = 0, j = 0, max = 0 ;
        u_char * uchr = (u_char *)uni;
        max = buf_size - 2;
        max += max ; 
        for(i = 0, j = 0; utf8[j] != '\0'; i += 2) {
            if (i > max) break;
            if(utf8[j] <= 0x7f) {
            	// ascii char, no need to be converted 
            	uchr[i+1] = 0x00 ; 
            	uchr[i] = utf8[j] ; 
            	j += 1 ; 
            } else {
            	uchr[i+1] = ((utf8[j] & 0x0F) << 4) + ((utf8[j+1] >> 2) & 0x0F);
            	uchr[i] = ((utf8[j+1] & 0x03) << 6) + (utf8[j+2] & 0x3F);
            	j += 3 ; 
            }
        }
        uchr[i] = '\0';
        uchr[i+1] = '\0';
        return i ; 
}

// calc the char offset start in hz file 
// s : hz going to be displayed 
// hzkmode : HZK12(12x12) or HZK16(16x16)
// return value : hz offset in hz file 
u_int ezfb_hz_offset(char *s, u_char hzkmod)
{
  u_int tmp_pos = 0 ;
  u_char wh = 0, qh = 0;
  wh = *s - 0xa1 ;
  qh = *(s + 1) - 0xa1 ;
  if(hzkmod == HZK12) tmp_pos = (wh * 94 + qh) * 24L ;
  else tmp_pos = (wh * 94 + qh) * 32L ;
  return tmp_pos ;
}

// read hz data from hz file 
// hz[32]   : store the hz result, hz 12x12 only need 
//	      24 bytes for 16x16 hz, we chose 32 bytes long
// pos      : char start offset position in hz file 
// hzkmod   : HZK12 or HZK16
// return   : 1 success, 0 failed 
int ezfb_read_hz(u_char hz[32], u_int pos, u_char hzkmod)
{
  FILE * fp = NULL ;
  if(hzkmod==HZK12) fp = g_fp_hzk12 ; 
  else fp = g_fp_hzk16 ; 
  
  // maybe rather slow
  //rewind(fp) ; 
  fseek(fp,pos,SEEK_SET) ;
  fread(hz,32,1,fp) ;
  return 1 ;
}

// display ascii char 
// x, y  : char position in lcd
// ch    : the ascii char
// color : the char color 
void ezfb_disp_ascii_chr(struct ezfb* fb, int x, int y, char ch, u_int color)
{
  u_char tmp_chr ;
  u_char i,j ;
  tmp_chr = (u_char)(ch) ;
  for(i = 0 ; i < 16 ; i++) {
      for(j = 0 ; j < 8 ; j++) {
	  if((g_ascii[tmp_chr * 16 + i] >> (7 - j)) & 0x01)
	     ezfb_put_pixel(fb, (x + j), (y + i), color) ; 
      }
  }
}

// display ascii char to other devices
// caller must give pf to handle put_pixel function
// x, y  : char position in pixel 
// ch    : ascii char 
// data  : user data
// pf    : user put pixel func
void ezfb_mem_ascii_chr(int x, int y, char ch, 
						PUT_PIXEL_FUNC pf, void * data) 
{
	u_char tmp_chr ;
  	u_char i, j ;
  	tmp_chr = (u_char)(ch) ;
  	for(i = 0 ; i < 16 ; i++) {
      for(j = 0 ; j < 8 ; j++) {
	  	if((g_ascii[tmp_chr * 16 + i] >> (7 - j)) & 0x01)
	  		(*pf)(data, (x + j), (y + i)) ; 
      }
  	}
}

//display ascii string, will auto sart a new line when displayed 
//chars count exceeds the preset line_chr_count 
// x, y           : output char pos
// line_chr_count : chars count in one line, if the * ch exceed the chars count,
//                  will start a new line to continue the chars
// s              : point to ascii string going to be displayed 
// color          : the char color 
void ezfb_disp_ascii_str(struct ezfb* fb, int x, int y,
			 int line_chr_count,
			 char * s, u_int color)
{
  int    tmpx = x ,tmpy = y ;
  int    disp_chr_count = 0 ;
  char * tmps = s ;

  while(*tmps != '\0') {
      ezfb_disp_ascii_chr(fb, tmpx, tmpy,*tmps++,color) ;
      disp_chr_count++ ;
      if(disp_chr_count >= line_chr_count) {
	  // if exceed the char count, start a new line 
	  tmpx = x ;
	  tmpy = tmpy + 12 ;
	  disp_chr_count = 0 ;
      } else tmpx = tmpx + 8 ;
  }
}

// same function as ezfb_disp_ascii_str, difference is 
// to display ascii string with user provided callback function
// x, y  : char position in pixel 
// line_chr_count : chars count in one line, if the * ch exceed the chars count,
//                  will start a new line to continue the chars
// s     : ascii string
// pf    : user put pixel func
// data  : user data
void ezfb_mem_ascii_str(int x, int y, int line_chr_count, char * s,
						PUT_PIXEL_FUNC pf, void * data)
{
	int    tmpx = x ,tmpy = y ;
  	int    disp_chr_count = 0 ;
  	char * tmps = s ;

  	while(*tmps != '\0') {
      ezfb_mem_ascii_chr(tmpx, tmpy, *tmps++, pf, data) ;
      disp_chr_count++ ;
      if(disp_chr_count >= line_chr_count) {
	  // if exceed the char count, start a new line 
	  tmpx = x ;
	  tmpy = tmpy + 12 ;
	  disp_chr_count = 0 ;
      } else tmpx = tmpx + 8 ;
  	}
}

// display 16x16 hz 
// x,y   : display pos in lcd 
// gb    : display char encoded in gb2312
// color : char color 
void ezfb_disp_hz16_chr(struct ezfb* fb, int x,int y,char * gb, u_int color)
{
  u_char i,j ;
  u_char hz[32] ; 
  if(ezfb_read_hz(hz, ezfb_hz_offset(gb,HZK16),HZK16)) {
      for(i = 0 ; i < 16 ; i++) {
	  	for(j = 0 ; j < 16 ; j++) {
	      if((hz[i * 2 + j / 8] >> (7 - j % 8)) & 0x01)
		 		ezfb_put_pixel(fb, (x + j), (y + i), color) ; 
	  	}
      }
  }
}

// same function as ezfb_disp_hz16_chr, difference is 
// to display hz 16x16 char with user provided callback function
// x,y   : display pos in lcd 
// gb    : display char encoded in gb2312
// pf    : user put pixel func
// data  : user data
void ezfb_mem_hz16_chr(int x, int y, char * gb, 
					   PUT_PIXEL_FUNC pf, void * data)
{
	u_char i,j ;
  	u_char hz[32] ; 
  	if(ezfb_read_hz(hz, ezfb_hz_offset(gb,HZK16),HZK16)) {
    	for(i = 0 ; i < 16 ; i++) {
	  		for(j = 0 ; j < 16 ; j++) {
	      		if((hz[i * 2 + j / 8] >> (7 - j % 8)) & 0x01)
		 			(*pf)(data, (x + j), (y + i)) ; 
	  		}
      	}
  	}
}

// display 12x12 hz 
// x, y : display pos in lcd 
// gb   : display char encoded in gb2312
// color: char color 
void ezfb_disp_hz12_chr(struct ezfb* fb, int x, int y, char * gb, u_int color)
{
  u_char i,j ;
  u_char hz[32] ; 
  if(ezfb_read_hz(hz, ezfb_hz_offset(gb, HZK12),HZK12)) {
      for(i = 0 ; i < 12 ; i++) {
	  	//12x12, only use 16 bits ahead, dismiss the left 
	  	for(j = 0 ; j < 12 ; j++) {
	      if((hz[i * 2 + j / 8] >> (7 - j % 8)) & 0x01)
		  	ezfb_put_pixel(fb, (x + j), (y + i), color) ; 
	  	}
      }
  }
}

// same function as ezfb_disp_hz12_chr, difference is 
// to display hz 12x12 char with user provided callback function
// x,y   : display pos in lcd 
// gb    : display char encoded in gb2312
// pf    : user put pixel func
// data  : user data
void ezfb_mem_hz12_chr(int x, int y, char * gb,
					   PUT_PIXEL_FUNC pf, void * data = NULL)
{
  u_char i,j ;
  u_char hz[32] ; 
  if(ezfb_read_hz(hz, ezfb_hz_offset(gb, HZK12),HZK12)) {
      for(i = 0 ; i < 12 ; i++) {
	  	//12x12, only use 16 bits ahead, dismiss the left 
	  	for(j = 0 ; j < 12 ; j++) {
	      if((hz[i * 2 + j / 8] >> (7 - j % 8)) & 0x01)
		  	(*pf)(data, (x + j), (y + i)) ; 
	  	}
      }
  }	
}

// display string contains both hz and ascii chars in 16x16 mode
// x,y   : display pos 
// color : font color 
// gb    : gb2312 encoded string, could mixed with ascii chars 
void ezfb_disp_mix16_str(struct ezfb* fb, int x, int y, char * gb, u_int color) 
{
  u_char * tmp_str = (u_char *)gb ;
  int    x_pos = x ;
  char   gb2312_hz[2] ;

  while(*tmp_str) {
      //if the x pos exceed the right edge of LCD break 
      if(x_pos >= 240) break ; 
      if(*tmp_str < 0xa0) {
	    // display ascii chars in 8x16 mode 
	    ezfb_disp_ascii_chr(fb, x_pos, y, *tmp_str++, color) ;
	    x_pos += 8 ;
      }	else {
	    // display hz in 16x16 mode
	    gb2312_hz[0] = *tmp_str++ ;
	    gb2312_hz[1] = *tmp_str++ ;
	    ezfb_disp_hz16_chr(fb, x_pos, y, gb2312_hz, color) ; 
	    x_pos += 16 ; 
      }
   }
}

// same function as ezfb_disp_mix16_str, difference is 
// to display ascii and gb2312 mixed string 16x16 with user 
// provided callback function
// x,y   : display pos in lcd 
// gb    : display char encoded in gb2312
// pf    : user put pixel func
// data  : user data
void ezfb_mem_mix16_str(int x, int y, char * gb,
						PUT_PIXEL_FUNC pf, void * data)
{
	u_char * tmp_str = (u_char *)gb ;
  	int    x_pos = x ;
  	char   gb2312_hz[2] ;

	while(*tmp_str) {
      //if the x pos exceed the right edge of LCD break 
      if(x_pos >= 240) break ; 
      if(*tmp_str < 0xa0) {
	    // display ascii chars in 8x16 mode 
	    ezfb_mem_ascii_chr(x_pos, y, *tmp_str++, pf, data) ;
	    x_pos += 8 ;
      }	else {
	    // display hz in 16x16 mode
	    gb2312_hz[0] = *tmp_str++ ;
	    gb2312_hz[1] = *tmp_str++ ;
	    ezfb_mem_hz16_chr(x_pos, y, gb2312_hz, pf, data) ; 
	    x_pos += 16 ; 
      }
   }
}

// display a 12x12 string 
// x,y  : display pos 
// gb   : display string encoded in gb2312
// color: string color 
void ezfb_disp_mix12_str(struct ezfb* fb, int x, int y, char * gb, u_int color) 
{
  u_char *  tmp_str = (u_char *)gb ;
  char    gb2312_hz[2] ; 
  int     x_pos = x ;  
  
  while(*tmp_str) {
      if(x_pos > 240) break ; //if the position overflow of the LCD
      if(*tmp_str < 0xa0) {
      	    // display ascii chars still in 8x16 mode 
	    	ezfb_disp_ascii_chr(fb, x_pos, y, *tmp_str++, color) ; 
	    	x_pos = x_pos + 8 ;
      } else {
	    	// display hz in 12x12 mode 
	    	gb2312_hz[0] = *tmp_str++ ;
	    	gb2312_hz[1] = *tmp_str++ ; 
	    	ezfb_disp_hz12_chr(fb, x_pos, y, gb2312_hz, color) ; 
	    	x_pos += 12 ;
      }
  }
}

// same function as ezfb_disp_mix12_str, difference is 
// to display ascii and gb2312 mixed string 12x12 with user 
// provided callback function
// x,y   : display pos in lcd 
// gb    : display char encoded in gb2312
// pf    : user put pixel func
// data  : user data
void ezfb_mem_mix12_str(int x, int y, char * gb,
						PUT_PIXEL_FUNC pf, void * data = NULL)
{
	u_char *tmp_str = (u_char *)gb ;
  	char    gb2312_hz[2] ; 
  	int     x_pos = x ;  
  
  	while(*tmp_str) {
    	if(x_pos > 240) break ; //if the position overflow of the LCD
      	if(*tmp_str < 0xa0) {
      	    // display ascii chars still in 8x16 mode 
	    	ezfb_mem_ascii_chr(x_pos, y, *tmp_str++, pf, data) ; 
	    	x_pos = x_pos + 8 ;
      	} else {
	    	// display hz in 12x12 mode 
	    	gb2312_hz[0] = *tmp_str++ ;
	    	gb2312_hz[1] = *tmp_str++ ; 
	    	ezfb_mem_hz12_chr(x_pos, y, gb2312_hz, pf, data) ; 
	    	x_pos += 12 ;
      	}
  	}
}

int ezfb_mix16_str_width(const char * gb)
{
  	int    x_pos = 0 ; 
  	while(*gb) {
      //if the x pos exceed the right edge of LCD break 
      if(x_pos >= 240) break ; 
      if(*gb < 0xa0) {
	    gb++ ; 
	    // ascii use 8x16 mode, 8 pixels width 
	    x_pos += 8 ;
      } else {
	    gb++ ; 
	    gb++ ; 
	    // hz 16x16 mode, 16 pixels width
	    x_pos += 16 ; 
      }
    }
    return x_pos ; 
}

int ezfb_mix12_str_width(const char * gb)
{
	int    x_pos = 0 ; 
  	while(*gb) {
      //if the x pos exceed the right edge of LCD break 
      if(x_pos >= 240) break ; 
      if(*gb < 0xa0) {
	    gb++ ; 
	    // ascii use 8x16 mode, 8 pixels width 
	    x_pos += 8 ;
      } else {
	    gb++ ; 
	    gb++ ; 
	    // hz 12x12 mode, 
	    // i don't know why it need 13 pixels width >:-( fuck this zk
	    x_pos += 12 ; 
      }
    }
    return x_pos ; 
}

